/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp._134_;


import cz.pecinovsky.english.lootp.manager.Painter;
import cz.pecinovsky.english.lootp.manager.Rectangle;


import cz.pecinovsky.english.lootp._134_.IModular_134_.IModular;
import cz.pecinovsky.english.lootp._134_.IRotable_136_.IRotable;


//import cz.pecinovsky.english.lootp._134_.RoadField_134_.RoadField;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++
//%I+
//
//import cz.pecinovsky.english.lootp.canvasmanager.Painter;
//import cz.pecinovsky.english.lootp.canvasmanager.Rectangle;
//%I-

import cz.pecinovsky.english.lootp.utility.NamedColor;
//%A+ >139
import cz.pecinovsky.english.lootp.utility.IO;
//%A-
import cz.pecinovsky.english.lootp.utility.Position;
import cz.pecinovsky.english.lootp.utility.Direction8;
//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */
public class RoadField_134_
{    private RoadField_134_() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----


/*******************************************************************************
 * Instance třídy {@code RoadField} představují části, z nichž budou sestaveny
 * cesty. Každá instance zná direction, kterým se přes ní projíždí,
 * a svého následníka, což je sourozenec, na nějž projíždějící objekt dojede.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public class RoadField implements IModular
{
//== CONSTANT CLASS ATTRIBUTES =================================================
//== VARIABLE CLASS ATTRIBUTES =================================================
//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ========
//== CONSTANT INSTANCE ATTRIBUTES ==============================================

    /** Rectangle představující plochu daného pole cesty na plátně. */
    private final Rectangle plocha;

    /** Směr, jímž je dané pole průjezdné. */
    private final Direction8 direction;



//== VARIABLE INSTANCE ATTRIBUTES ==============================================

    /** Následník tohoto pole na cestě = pole, na které se přijede
     *  po projetí tohoto pole v jeho směru.  */
    private RoadField následník;
//%A+ >144

    /** Počet žádostí o zablokování pole. */
    private int blokací = 0;

    /** Sdružené pole, tj. pole, které se s tímto překrývá.
     * Jakmile na pole někdo vjede, musí zablokovat sdružené pole. */
    private RoadField sdružené = null;

    /** Objekt, který dané pole navštívil a který je musí
     *  při odjezdu explicitně opustit;
     *  pole je schopno akceptovat v daný okamžik nejvýše jednu návštěvu.
     *  Prázdný odkaz symbolizuje pole bez návštěvníka, tj. pole,
     *  které je možno navštívit. */
    private IRotable návštěva = null;
//%A-



//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * V zadané pozici vytvoří počáteční pole cesty průjezdné zadaným směrem.
     * Protože konstrukcí tohoto pole zahajujeme výstavbu okruhu,
     * označujeme konstruktor jako <i>zahajovací</i>.
     *
     * @param pozice Position pole
     * @param module  Velikost strany zabraného čtverce
     * @param direction   Směr, jímž bude pole průjezdné
     * @param color  NamedColor pole
     */
    public RoadField(Position pozice, int module, Direction8 direction, NamedColor color)
    {
        this.plocha = new Rectangle(pozice.x, pozice.y, module, module, color);
        this.direction   = direction;
    }


    /***************************************************************************
     * Vytvoří nové pole cesty, které bude navazovat na zadaného předchůdce
     * a bude průjezdné zadaným směrem.
     * Protože konstrukcí tohoto pole pokračujeme ve výstavbě okruhu,
     * označujeme konstruktor jako <i>pokračovací</i>.
     *
     * @param předchůdce Pole, na něž bude vytvářené pole navazovat
     * @param direction       Směr, jímž bude pole průjezdné
     */
    public RoadField(RoadField předchůdce, Direction8 direction)
    {
        int    module  = předchůdce.getModule();
        Position pozice = předchůdce.direction.nextPosition(předchůdce.getPosition(),
                                                    module);
        NamedColor  color  = předchůdce.plocha.getColor();

        this.plocha = new Rectangle(pozice.x, pozice.y, module, module, color);
        this.direction   = direction;
        předchůdce.následník = this;
    }


    /***************************************************************************
     * Vytvoří nové pole cesty, které bude navazovat na zadaného předchůdce,
     * bude průjezdné zadaným směrem a bude na ně navazovat zadaný následník.
     * Protože konstrukcí tohoto pole uzavíráme okruh a tím i jeho výstavbu,
     * označujeme konstruktor jako <i>uzavírací</i>.
     *
     * @param předchůdce  Pole, na něž bude vytvářené pole navazovat
     * @param direction        Směr, jímž bude pole průjezdné
     * @param následník   Pole, které bude navazovat na vytvářené pole
     */
    public RoadField(RoadField předchůdce, Direction8 direction, RoadField následník)
    {
        this(předchůdce, direction);
//%I+ <139
//        this.následník = následník;
//%I-
//%A+ >139
        Position další = direction.nextPosition(getPosition(), getModule());
        if (další.equals(následník.getPosition())) {
            this.následník = následník;
        } else {
            IO.inform(
               "Při uzavírání okruhu si neodpovídají pozice navazujících polí");
        }
//%A-
    }



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================

    /***************************************************************************
     * Vrátí délku strany bloku.
     *
     * @return Délka strany bloku
     */
    @Override
    public int getModule()
    {
        return plocha.getWidth();
    }


    /***************************************************************************
     * Nastaví novou délku strany bloku.
     *
     * @param module Nově nastavovaná délka strany bloku
     */
    @Override
    public void setModule(int module)
    {
//%A+ >139
        if (module <= 0) {
            throw new IllegalArgumentException(
                "\nVelikost modulu musí být nezáporná - zadáno " + module);
        }
//%A-
        plocha.setSize(module);
    }


    /***************************************************************************
     * Vrádí následníka daného bloku cesty.
     *
     * @return Následník daného bloku
     */
    public RoadField getDalší()
    {
        return následník;
    }


    /***************************************************************************
     * Vrátí přepravku se souřadnicemi instance.
     *
     * @return  Přepravka se souřadnicemi instance
     */
    @Override
    public Position getPosition()
    {
        return plocha.getPosition();
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param pozice  Nová pozice instance
     */
    @Override
    public void setPosition(Position pozice)
    {
        plocha.setPosition(pozice);
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozice instance
     * @param y   Nová y-ová pozice instance
     */
    @Override
    public void setPosition(int x, int y)
    {
        plocha.setPosition(x, y);
    }


    /***************************************************************************
     * Vrátí direction, jímž je daný blok průjezdný.
     *
     * @return Směr, jímž je blok průjedzný
     */
    public Direction8 getSměr()
    {
        return direction;
    }

//%A+ >144

    /***************************************************************************
     * Vrátí informaci o tom, je-li pole volné nebo blokované.
     *
     * @return {@code true} je-li pole volné a je možné na ně vjet,
     *         v opačném případě {@code false}
     */
    public boolean isVolné()
    {
        return blokací > 0;
    }

//%A-


//%X+
    @Override public int getX() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    @Override public int getY() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
//%X-
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param painter Painter, které nakreslí instanci
     */
    @Override
    public void paint(Painter painter)
    {
        plocha.paint(painter);
    }


    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "PoleCesty_(" + plocha.getPosition() + ", Směr=" + direction +
               ", Modul=" + plocha.getWidth() + ")";
    }

//%A+ >144

    /***************************************************************************
     * Zablokuje dané pole, tj. zvýší počet jeho blokací o jedničku.
     */
    public void zablokuj()
    {
        blokací++;
    }


    /***************************************************************************
     * Odblokuje dané pole, tj. sníží počet jeho blokací o jedničku.
     * Dokud je počet blokací > 1, neměl by na pole nikdo vjet.
     */
    public void odblokuj()
    {
        if (blokací <= 0) {
            throw new IllegalStateException(
                    "\nPokus o odblokování odblokovaného pole: " + this);
        }
        blokací--;
    }


    /***************************************************************************
     * Sdruži své pole se zadaným polem. Sdružovat je možné pouze pole,
     * které ještě není s nikým sdružené.
     *
     * @param pole Pole, s nímž se dané pole sdružuje
     */
    public void sdružS(RoadField pole)
    {
        if (sdružené != null) {
            throw new IllegalStateException(
                "\nPokus o sdružení již sdruženého pole: toto=" + this +
                ", sdružované=" + pole);
        }
        this.sdružené = pole;
    }


    /***************************************************************************
     * Přivítá zadaný objekt, zablokuje se pro všechny ostatní a
     * současně zablokuje i případné sdružené pole.
     * Parametr je tu pouze pro zvýšení kontroly, že pole bude následně
     * opouštět týž objekt, který jej nyní navštívil.
     *
     * @param návštěva Objekt, který dané pole navštívil, je tu pro kontrolu,
     *                 že týž objekt následně pole opouští
     */
    public void příjezd(IRotable návštěva)
    {
        if (this.návštěva != null) {
            throw new IllegalStateException(
                "\nPokus o navštívení pole s návštěvou: pole=" + this +
                ", návštěva=" + this.návštěva + ", další=" + návštěva);
        }
        if (! isVolné()) {
            throw new IllegalStateException(
                "\nPokus o navštívení zablokovaného pole: pole=" + this +
                ", návštěva=" + návštěva);
        }
        this.návštěva = návštěva;
        zablokuj();
        if (sdružené != null) {
            sdružené.zablokuj();
        }
    }


    /***************************************************************************
     * Přivítá zadaný objekt, zablokuje se pro všechny ostatní a
     * současně zablokuje i případné sdružené pole.
     * Parametr je tu pouze pro zvýšení kontroly, že pole bude následně
     * opouštět týž objekt, který jej nyní navštívil.
     *
     * @param návštěva Objekt, který dané pole navštívil, je tu pro kontrolu,
     *                 že týž objekt následně pole opouští
     */
    public void odjezd(IRotable návštěva)
    {
        if (this.návštěva != návštěva) {
            throw new IllegalStateException(
                "\nPole se pokouší opustit jiný objekt než ten," +
                "který je navštívil: pole=" + this +
                ", návštěva=" + this.návštěva + ", opouští=" + návštěva);
        }
        odblokuj();
        návštěva = null;
        if (sdružené != null) {
            sdružené.odblokuj();
        }
    }

//%A-


//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED TYPES AND INNER CLASSES ==========================================
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        RoadField inst = new RoadField();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
    }

//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        System.exit(0);
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
}
